/**
 * Copyright (C) 2011 Andrew C. Love (DNC) <dnc.app.sup@gmail.com>
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *         http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.dnc.cloak.service;

import java.io.IOException;
import java.security.KeyStore;
import java.security.KeyStoreException;
import java.security.NoSuchAlgorithmException;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.UnrecoverableKeyException;
import java.security.cert.Certificate;
import java.security.cert.CertificateException;
import java.util.ArrayList;
import java.util.List;

import javax.crypto.SecretKey;
import javax.crypto.spec.SecretKeySpec;

import org.apache.log4j.Logger;

import com.dnc.cloak.framework.context.Context;
import com.dnc.cloak.framework.persistence.CrudResult;
import com.dnc.cloak.framework.persistence.gen.Keystore;
import com.dnc.cloak.framework.persistence.gen.KeystoreEntry;
import com.dnc.cloak.framework.persistence.gen.KeystoreEntryExample;
import com.dnc.cloak.framework.persistence.gen.KeystoreExample;
import com.dnc.cloak.framework.security.encryption.ConfidentialData;
import com.dnc.cloak.framework.security.encryption.EncryptedData;
import com.dnc.cloak.framework.security.encryption.EncryptionException;
import com.dnc.cloak.framework.security.encryption.EncryptionProperties;
import com.dnc.cloak.framework.security.encryption.EncryptionProvider;
import com.dnc.cloak.framework.security.encryption.EncryptionUtil;
import com.dnc.cloak.framework.security.encryption.KeyContext;
import com.dnc.cloak.framework.security.encryption.KeystoreBean;
import com.dnc.cloak.framework.service.AbstractService;
import com.dnc.cloak.framework.service.ServiceException;
import com.dnc.cloak.service.gen.KeystoreEntryService;
import com.dnc.cloak.service.gen.KeystoreService;


public class EncryptionServiceImpl extends AbstractService implements EncryptionService {
	    
    private KeystoreService keystoreService;
    private KeystoreEntryService keystoreEntryService;
    private static final Logger logger = Logger.getLogger(EncryptionServiceImpl.class.getName());
    
	
    public KeystoreService getKeystoreService() {
        return keystoreService;
    }

    public void setKeystoreService(KeystoreService keystoreService) {
        this.keystoreService = keystoreService;
    }

    public KeystoreEntryService getKeystoreEntryService() {
        return keystoreEntryService;
    }

    public void setKeystoreEntryService(KeystoreEntryService keystoreEntryService) {
        this.keystoreEntryService = keystoreEntryService;
    }

    private synchronized KeystoreBean getKeystoreBean(Context context, KeyContext keyContext) throws EncryptionException, ServiceException {

        if (logger.isDebugEnabled()) {
            logger.debug("EncryptionServiceImpl.KeystoreBean() keystore=" + keyContext.getKeystoreName());
        }
        
        KeystoreBean keystoreBean = EncryptionServiceHelper.getKeyStoreBean(keyContext.getKeystoreName());
        
        try {
            if (keystoreBean == null) {
                if (keyContext.getKeystoreSource() == KeyContext.KeyStoreSource.Database) {                
                    keystoreBean = loadKeytoreBeanFromDatabase(context, keyContext, keystoreBean);
                }
                else if (keyContext.getKeystoreSource() == KeyContext.KeyStoreSource.Classpath){                    
                    keystoreBean = loadKeytoreBeanFromClasspath(context, keyContext, keystoreBean);                    
                }
                else if (keyContext.getKeystoreSource() == KeyContext.KeyStoreSource.File){                    
                    keystoreBean = loadKeytoreBeanFromFile(context, keyContext, keystoreBean);                    
                }                
            }
        }
        catch (KeyStoreException e) {
            throw new EncryptionException(e);
        }
        catch (NoSuchAlgorithmException e) {
            throw new EncryptionException(e);
        }
        catch (CertificateException e) {
            throw new EncryptionException(e);
        }
        catch (IOException e) {
            throw new EncryptionException(e);
        }
        catch (Exception e) {
            throw new EncryptionException(e);
        }
        return keystoreBean;   
    }

    private KeystoreBean loadKeytoreBeanFromDatabase(Context context,
            KeyContext keyContext, KeystoreBean keystoreBean)
            throws ServiceException, EncryptionException, Exception,
            KeyStoreException, IOException, NoSuchAlgorithmException,
            CertificateException {
        KeystoreExample keystoreExample = new KeystoreExample();
        com.dnc.cloak.framework.persistence.gen.KeystoreExample.Criteria keyStorecriteria = keystoreExample.createCriteria();
        keyStorecriteria.andKeystoreNameEqualTo(keyContext.getKeystoreName());
   
        CrudResult<Keystore> keystoreResult = keystoreService.crud(context, null, keystoreExample);
        
        if (keystoreResult.getNumSelect() > 0) {
            logger.info("keystore:" + keyContext.getKeystoreName() + ":exists");
   
            KeystoreEntryExample keystoreEntryExample = new KeystoreEntryExample();
            com.dnc.cloak.framework.persistence.gen.KeystoreEntryExample.Criteria keystoreEntryExampleCriteria = keystoreEntryExample.createCriteria();
            keystoreEntryExampleCriteria.andKeystoreNameEqualTo(keyContext.getKeystoreName());
            CrudResult<KeystoreEntry> keystoreEntryResult = keystoreEntryService.crud(context, null, keystoreEntryExample);
            if (keystoreEntryResult.getNumSelect() > 0) {
                keystoreBean = EncryptionServiceHelper.createKeystoreBean(context, keystoreResult.getFirstResult(), keystoreEntryResult.getResult());
                EncryptionServiceHelper.addKeystore(keystoreBean);
            }
            else {
                //Error- Keystore record exists, but no alias record
                throw new EncryptionException("Keystore record exists, but no alias record");
            }
        }
        else {
            logger.info("keystore:" + keyContext.getKeystoreName() + ":does not exist");
   
            // Need to create the keystore and insert into database
            keystoreBean = EncryptionServiceHelper.createKeyStore(context, keyContext.getKeystoreName(), keyContext.getAlias());
   
            logger.info(keystoreBean.toString());
   
            List<Keystore> keystoreList = new ArrayList<Keystore>();
            keystoreList.add(keystoreBean.getKeystore());
   
            keystoreService.crud(context, keystoreList, null);
            keystoreEntryService.crud(context, keystoreBean.getKeystoreEntries(), null);
   
            EncryptionServiceHelper.addKeystore(keystoreBean);
        }
        return keystoreBean;
    }   
    
    private KeystoreBean loadKeytoreBeanFromClasspath(Context context,
            KeyContext keyContext, KeystoreBean keystoreBean)
            throws ServiceException, EncryptionException, Exception,
            KeyStoreException, IOException, NoSuchAlgorithmException,
            CertificateException {
        
        
            KeyStore keyStore = EncryptionUtil.loadKeyStoreFromClasspath(keyContext.getKeystoreLocation(), keyContext.getProviderClassName(), keyContext.getKeystoreType(), keyContext.getToken());
            keystoreBean = EncryptionServiceHelper.createKeystoreBean(context,keyStore,keyContext);
            EncryptionServiceHelper.addKeystore(keystoreBean);
        
        return keystoreBean;
    }       

    private KeystoreBean loadKeytoreBeanFromFile(Context context,
            KeyContext keyContext, KeystoreBean keystoreBean)
            throws ServiceException, EncryptionException, Exception,
            KeyStoreException, IOException, NoSuchAlgorithmException,
            CertificateException {
        
        
            KeyStore keyStore = EncryptionUtil.loadKeyStoreFromFile(keyContext.getKeystoreLocation(), keyContext.getProviderClassName(), keyContext.getKeystoreType(), keyContext.getToken());
            keystoreBean = EncryptionServiceHelper.createKeystoreBean(context,keyStore,keyContext);
            EncryptionServiceHelper.addKeystore(keystoreBean);
        
        return keystoreBean;
    }       

//    // Check the certificate expiration date
//    try {
//        ((X509Certificate) ksm.getCertificate()).checkValidity();
//    }
//    catch (Exception ex) {
//        if (logger.isDebugEnabled()) {
//            logger.debug("keystore is invalid" + keyContext.getKeyStoreName());
//        }
//        
//        if (ksm.getCertAutoGenerateOnExpire()) {
//            // The cert is not valid so create a new one
//            logger.error("Exception occurred while attempting to check validity of certificate.  Creating a new certificate.", ex);
//
//            keyContext.setKeystoreName(ksm.getKeyStoreName());
//            keyContext.setKeystoreId(ksm.getKeyStoreID().intValue());
//            KeyStoreManager.removeKeyStoreManager(keyContext.getKeyStoreName());
//            // Get the properties so we can use them for update
//            Properties jceProperties = ksm.getJCEProperties();
//            // Create a new KSM
//            ksm = KeyStoreManager.getInstance(keyContext.getKeyStoreName());
//            // Set the previous properties
//            keyContext.setJCEProperties(jceProperties);
//            // Update the database with new keystore
//            
//            KeyContext keyContextResult = updateKeyStore(context, keyContext);
//            ksm.setKeyStore(keyContextResult.getKeystoreContent(), keyContextResult.getJCEProperties());
//            ksm.setLstUptTime(keyContextResult.getLstUptTime());
//            ksm.setKeyStoreID(keyContextResult.getKeystoreId().longValue());
//        }
//        else {
//            throw new ServiceException(keyContext.getKeyStoreName() + ":Certificate is invalid,auto cert is false:", ex);
//        }
//    }
//}
//else {
//    //Retrieve from file
//    loadKeyStorefromFileSystem(context, keyContext, ksm);
//    
//    // Check the certificate expiration date
//    try {
//        ((X509Certificate) ksm.getCertificate()).checkValidity();
//    }
//    catch (Exception ex) {
//        if (logger.isDebugEnabled()) {
//            logger.debug("keystore is invalid" + keyContext.getKeyStoreName());
//        }
//        
//        throw new ServiceException(keyContext.getKeyStoreName() + ":Certificate is invalid,auto cert is false:", ex);                   
//    }
//}
//
//return ksm;
//
//}
//catch (Exception ex) {
//throw new EncryptionException(keyContext.getKeyStoreName() + "Exception occurred while attempting to getKeyStoreManager.", ex);
//}
//
//}    
    
	
    @Override
    public ConfidentialData decryptSessionKey(Context context, KeyContext keyContext, EncryptedData encryptedData) throws EncryptionException, ServiceException {
    	
    	try {
    	    
			byte[] keyLengthByteArray = new byte[EncryptionProperties.SESSION_KEY_LENGTH];
			System.arraycopy(encryptedData.getData(), 0, keyLengthByteArray, 0, EncryptionProperties.SESSION_KEY_LENGTH);
			String sessionKeyLengthHex = new String(keyLengthByteArray);
			int sessionKeyLength = Integer.parseInt(sessionKeyLengthHex, 16);
			
			//get the encrypted session key 
			byte[]encryptedSessionKey = new byte[sessionKeyLength];
			System.arraycopy(encryptedData.getData(), EncryptionProperties.SESSION_KEY_LENGTH, encryptedSessionKey, 0, sessionKeyLength);
			ConfidentialData decryptedSessionKey = decryptAsymmetric(context, keyContext, new EncryptedData(encryptedSessionKey));

            //Get the symmetric key just for the algorithm
			keyContext = getSymmetricKey(context, keyContext);
			//Recreate the generated session key with the symmetric algorithm
            SecretKey secretKey = new SecretKeySpec(decryptedSessionKey.getData(), keyContext.getAlgorithm());
            keyContext.setSymmetricKey(secretKey);

			//get the encrypted data
			int encryptedPayloadLength = encryptedData.getData().length - (sessionKeyLength + EncryptionProperties.SESSION_KEY_LENGTH);
			byte[]encryptedPayload = new byte[encryptedPayloadLength];
			System.arraycopy(encryptedData.getData(), (sessionKeyLength + EncryptionProperties.SESSION_KEY_LENGTH), encryptedPayload, 0, encryptedPayloadLength);

            // Now decrypt the data with the session key
			//Finally decrypt the data
			ConfidentialData decryptedPayload = decryptSymmetric(context, keyContext, new EncryptedData(encryptedPayload));

			return decryptedPayload;
			
		} 
    	catch (NumberFormatException ex) {
			throw new EncryptionException(ex);
		} 	
    }
    
    @Override
    public EncryptedData encryptSessionKey(Context context, KeyContext keyContext, ConfidentialData confidentialData) throws EncryptionException, ServiceException {

        //Get the secret key
    	KeyContext secretKeyContext = createSymmetricKey(context,keyContext); 
    	
    	//encrypt data with symmetric
    	secretKeyContext.setSymmetricEncryptionMode();
    	EncryptedData data = encryptSymmetric(context, secretKeyContext, confidentialData);
    	
    	//Get the public key
    	KeyContext publicKeyContext = getPublicKey(context, keyContext);
    	
    	//Encrypt the symmetric key
    	ConfidentialData confidentialDataSecretKey = new ConfidentialData(secretKeyContext.getSymmetricKey().getEncoded());        	
    	EncryptedData encryptedKeyData =  encryptAsymmetric(context, publicKeyContext, confidentialDataSecretKey );

    	//get the required byte arrays
    	String encryptedKeyDataLength = EncryptionUtil.getHexString(encryptedKeyData.getData().length, EncryptionProperties.SESSION_KEY_LENGTH);
    	
    	logger.info("encryptedKeyDataLength:" + encryptedKeyDataLength);
    	
    	byte[] keyLengthByteArray = encryptedKeyDataLength.getBytes();        	
    	byte[] encryptedKeyArray = encryptedKeyData.getData();        	
    	byte[] encryptedDataArray = data.getData();

    	//Pack the data
    	int packedDataSize = keyLengthByteArray.length + encryptedKeyArray.length + encryptedDataArray.length;
    	byte[] packedData = new byte[packedDataSize]; 
    	System.arraycopy(keyLengthByteArray, 0, packedData, 0, keyLengthByteArray.length);
    	System.arraycopy(encryptedKeyArray, 0, packedData, keyLengthByteArray.length, encryptedKeyArray.length);
    	System.arraycopy(encryptedDataArray, 0, packedData, keyLengthByteArray.length + encryptedKeyArray.length, encryptedDataArray.length);
    	
    	EncryptedData encryptedData = new EncryptedData(packedData);    	
          
        return encryptedData;
    
    }
    
    @Override
    public EncryptedData encryptSymmetric(Context context, KeyContext keyContext, ConfidentialData confidentialData) throws EncryptionException, ServiceException{
        KeystoreBean keystoreBean = getKeystoreBean(context,keyContext);
        
        EncryptionProvider encryptor = null;

        try {            
            keyContext.setSymmetricEncryptionMode();
            encryptor = EncryptionServiceHelper.getEncryptionProvider(context, keyContext, keystoreBean, keyContext.getAlias());
            byte[] encryptedValue = encryptor.encryptByteArray(keyContext.getSymmetricKey(), confidentialData.getData());
            EncryptedData encryptedData = new EncryptedData(encryptedValue);
    
            return encryptedData;
        }
        catch (ClassNotFoundException ex) {
            throw new EncryptionException("ClassNotFoundException occurred while attempting to encrypt data.", ex);
        }
        catch (InstantiationException ex) {
            throw new EncryptionException("InstantiationException occurred while attempting to encrypt data.", ex);
        }
        catch (IllegalAccessException ex) {
            throw new EncryptionException("IllegalAccessException occurred while attempting to encrypt data.", ex);
        }
        catch (Exception ex) {
            throw new EncryptionException("Exception occurred while attempting to encrypt data.", ex);
        }
    }
    
    @Override
    public ConfidentialData decryptSymmetric(Context context, KeyContext keyContext, EncryptedData encryptedData) throws EncryptionException, ServiceException {
        KeystoreBean keystoreBean = getKeystoreBean(context,keyContext);
        
        EncryptionProvider encryptor = null;

        try {            
            keyContext.setSymmetricEncryptionMode();
            encryptor = EncryptionServiceHelper.getEncryptionProvider(context, keyContext, keystoreBean, keyContext.getAlias());
            byte[] decryptedValue = encryptor.decryptByteArray(keyContext.getSymmetricKey(), encryptedData.getData());
            ConfidentialData decryptedData = new ConfidentialData(decryptedValue);
    
            return decryptedData;
        }
        catch (ClassNotFoundException ex) {
            throw new EncryptionException("ClassNotFoundException occurred while attempting to encrypt data.", ex);
        }
        catch (InstantiationException ex) {
            throw new EncryptionException("InstantiationException occurred while attempting to encrypt data.", ex);
        }
        catch (IllegalAccessException ex) {
            throw new EncryptionException("IllegalAccessException occurred while attempting to encrypt data.", ex);
        }
        catch (Exception ex) {
            throw new EncryptionException("Exception occurred while attempting to encrypt data.", ex);
        }
    }

    @Override
    public EncryptedData encryptAsymmetric(Context context, KeyContext keyContext, ConfidentialData confidentialData) throws EncryptionException, ServiceException {
        KeystoreBean keystoreBean = getKeystoreBean(context,keyContext);
        EncryptionProvider encryptor = null;

        try {            
            keyContext.setAsymmetricEncryptionMode();
            encryptor = EncryptionServiceHelper.getEncryptionProvider(context, keyContext, keystoreBean, keyContext.getAlias());
            byte[] encryptedValue = encryptor.encryptByteArray(keyContext.getPublicKey(), confidentialData.getData());
            EncryptedData encryptedData = new EncryptedData(encryptedValue);
    
            return encryptedData;
        }
        catch (ClassNotFoundException ex) {
            throw new EncryptionException("ClassNotFoundException occurred while attempting to encrypt data.", ex);
        }
        catch (InstantiationException ex) {
            throw new EncryptionException("InstantiationException occurred while attempting to encrypt data.", ex);
        }
        catch (IllegalAccessException ex) {
            throw new EncryptionException("IllegalAccessException occurred while attempting to encrypt data.", ex);
        }
        catch (Exception ex) {
            throw new EncryptionException("Exception occurred while attempting to encrypt data.", ex);
        }
    }

    @Override
    public ConfidentialData decryptAsymmetric(Context context, KeyContext keyContext, EncryptedData encryptedData) throws EncryptionException, ServiceException {
        EncryptionProvider encryptor = null;
        KeystoreBean keystoreBean = getKeystoreBean(context,keyContext);

        try {            
            keyContext.setAsymmetricEncryptionMode();
            encryptor = EncryptionServiceHelper.getEncryptionProvider(context, keyContext, keystoreBean, keyContext.getAlias());
            byte[] decryptedValue = encryptor.decryptByteArray(keyContext.getPrivateKey(), encryptedData.getData());
            ConfidentialData decryptedData = new ConfidentialData(decryptedValue);
    
            return decryptedData;
        }
        catch (ClassNotFoundException ex) {
            throw new EncryptionException("ClassNotFoundException occurred while attempting to encrypt data.", ex);
        }
        catch (InstantiationException ex) {
            throw new EncryptionException("InstantiationException occurred while attempting to encrypt data.", ex);
        }
        catch (IllegalAccessException ex) {
            throw new EncryptionException("IllegalAccessException occurred while attempting to encrypt data.", ex);
        }
        catch (Exception ex) {
            throw new EncryptionException("Exception occurred while attempting to encrypt data.", ex);
        }
    }

    @Override
    public KeyContext getSymmetricKey(Context context, KeyContext keyContext) throws EncryptionException, ServiceException{
        KeystoreBean keystoreBean = getKeystoreBean(context,keyContext);
        KeystoreEntry keystoreEntry = keystoreBean.getKeystoreEntryMap().get(keyContext.getAlias());
        try {
            SecretKey secretKey = EncryptionServiceHelper.getSymmetricKey(keystoreBean, keyContext.getAlias());
            keyContext.setSymmetricKey(secretKey);
            
            keyContext.setAlgorithm(keystoreEntry.getKeystoreEntrySymAlgorithm());
            keyContext.setTransformation(keystoreEntry.getKeystoreEntrySymTransformation());
            keyContext.setLocation(keystoreBean.getKeystore().getKeystoreLocation());
            keyContext.setProviderClassName(keystoreBean.getKeystore().getKeystoreJceProvider());
            
            if (logger.isDebugEnabled()) logger.debug("keystore=" + keyContext.getKeystoreName());
        }
        catch (UnrecoverableKeyException e) {
            throw new EncryptionException("UnrecoverableKeyException", e);
        }
        catch (KeyStoreException e) {
            throw new EncryptionException("KeyStoreException", e);
        }
        catch (NoSuchAlgorithmException e) {
            throw new EncryptionException("NoSuchAlgorithmException", e);
        }
        catch (Exception e) {
            throw new EncryptionException("Exception", e);
        }
        return keyContext;
    }
    
    @Override
    public KeyContext createSymmetricKey(Context context, KeyContext keyContext) throws EncryptionException, ServiceException {
        KeystoreBean keystoreBean = getKeystoreBean(context,keyContext);
        KeystoreEntry keystoreEntry = keystoreBean.getKeystoreEntryMap().get(keyContext.getAlias());

        try {
            SecretKey secretKey = EncryptionServiceHelper.createSymmetricKey(keystoreBean, keyContext.getAlias());
            keyContext.setSymmetricKey(secretKey);
            
            keyContext.setAlgorithm(keystoreEntry.getKeystoreEntrySymAlgorithm());
            keyContext.setTransformation(keystoreEntry.getKeystoreEntrySymTransformation());
            keyContext.setLocation(keystoreBean.getKeystore().getKeystoreLocation());
            keyContext.setProviderClassName(keystoreBean.getKeystore().getKeystoreJceProvider());
            
            if (logger.isDebugEnabled()) logger.debug("keystore=" + keyContext.getKeystoreName());
        }
        catch (KeyStoreException ex) {
            throw new EncryptionException("Exception occurred while attempting to createSymmetricKey.", ex);
        }
        catch (Exception ex) {
            throw new EncryptionException("Exception occurred while attempting to createSymmetricKey.", ex);
        }
        return keyContext;
    }
    
    @Override
    public KeyContext getPrivateKey(Context context, KeyContext keyContext)throws EncryptionException, ServiceException {
        KeystoreBean keystoreBean = getKeystoreBean(context,keyContext);
        KeystoreEntry keystoreEntry = keystoreBean.getKeystoreEntryMap().get(keyContext.getAlias());
        try {
            PrivateKey privateKey = EncryptionServiceHelper.getPrivateKey(keystoreBean, keyContext.getAlias());
            keyContext.setPrivateKey(privateKey);
            
            keyContext.setAlgorithm(keystoreEntry.getKeystoreEntryPkiAlgorithm());
            keyContext.setTransformation(keystoreEntry.getKeystoreEntryPkiTransformation());
            keyContext.setLocation(keystoreBean.getKeystore().getKeystoreLocation());
            keyContext.setProviderClassName(keystoreBean.getKeystore().getKeystoreJceProvider());
            
            if (logger.isDebugEnabled()) logger.debug("keystore=" + keyContext.getKeystoreName());
        }
        catch (UnrecoverableKeyException e) {
            throw new EncryptionException("UnrecoverableKeyException", e);
        }
        catch (KeyStoreException e) {
            throw new EncryptionException("KeyStoreException", e);
        }
        catch (NoSuchAlgorithmException e) {
            throw new EncryptionException("NoSuchAlgorithmException", e);
        }
        catch (Exception e) {
            throw new EncryptionException("Exception", e);
        }
        return keyContext;
    }

    @Override
    public KeyContext getPublicKey(Context context, KeyContext keyContext) throws EncryptionException, ServiceException{
        KeystoreBean keystoreBean = getKeystoreBean(context,keyContext);
        KeystoreEntry keystoreEntry = keystoreBean.getKeystoreEntryMap().get(keyContext.getAlias());
        try {
            PublicKey publicKey = EncryptionServiceHelper.getPublicKey(keystoreBean, keyContext.getAlias());
            keyContext.setPublicKey(publicKey);

            keyContext.setAlgorithm(keystoreEntry.getKeystoreEntryPkiAlgorithm());
            keyContext.setTransformation(keystoreEntry.getKeystoreEntryPkiTransformation());
            keyContext.setLocation(keystoreBean.getKeystore().getKeystoreLocation());
            keyContext.setProviderClassName(keystoreBean.getKeystore().getKeystoreJceProvider());
            
            if (logger.isDebugEnabled()) logger.debug("keystore=" + keyContext.getKeystoreName());
        }
        catch (KeyStoreException e) {
            throw new EncryptionException("KeyStoreException", e);
        }
        catch (Exception e) {
            throw new EncryptionException("Exception", e);
        }
        return keyContext;
    }
    
    @Override
    public KeyContext getCertificate(Context context, KeyContext keyContext) throws EncryptionException, ServiceException{
        KeystoreBean keystoreBean = getKeystoreBean(context,keyContext);
        KeystoreEntry keystoreEntry = keystoreBean.getKeystoreEntryMap().get(keyContext.getAlias());
        try {
            Certificate certificate = EncryptionServiceHelper.getCertificate(keystoreBean, keyContext.getAlias());
            keyContext.setCertificate(certificate);
            
            keyContext.setAlgorithm(keystoreEntry.getKeystoreEntryPkiAlgorithm());
            keyContext.setTransformation(keystoreEntry.getKeystoreEntryPkiTransformation());
            keyContext.setLocation(keystoreBean.getKeystore().getKeystoreLocation());
            keyContext.setProviderClassName(keystoreBean.getKeystore().getKeystoreJceProvider());
            
            if (logger.isDebugEnabled()) logger.debug("keystore=" + keyContext.getKeystoreName());
        }
        catch (KeyStoreException e) {
            throw new EncryptionException("KeyStoreException", e);
        }
        catch (Exception e) {
            throw new EncryptionException("Exception", e);
        }
        
        return keyContext;
        
    }
    	
}
